package com.icedevcloud.upms.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.icedevcloud.common.core.exception.ApiException;
import com.icedevcloud.common.core.page.PageResult;
import com.icedevcloud.upms.controller.admin.role.dto.AddRoleReqDto;
import com.icedevcloud.upms.controller.admin.role.dto.RolePageReqDto;
import com.icedevcloud.upms.controller.admin.role.dto.SetRoleStatusReqDto;
import com.icedevcloud.upms.controller.admin.role.dto.UpdateRoleReqDto;
import com.icedevcloud.upms.entity.SysPermission;
import com.icedevcloud.upms.entity.SysRole;
import com.icedevcloud.upms.entity.SysRolePermission;
import com.icedevcloud.upms.entity.SysUserRole;
import com.icedevcloud.upms.mapper.SysRoleMapper;
import com.icedevcloud.upms.service.ISysPermissionService;
import com.icedevcloud.upms.service.ISysRolePermissionService;
import com.icedevcloud.upms.service.ISysRoleService;
import com.icedevcloud.upms.service.ISysUserRoleService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 角色表 服务实现类
 * </p>
 *
 * @author XiaoBingBy
 * @since 2023-08-13
 */
@RequiredArgsConstructor
@Service
public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> implements ISysRoleService {

    private final ISysUserRoleService iSysUserRoleService;
    private final ISysPermissionService iSysPermissionService;
    private final ISysRolePermissionService iSysRolePermissionService;

    @Override
    public PageResult<SysRole> rolePage(RolePageReqDto reqDto) {
        Page<SysRole> page = new Page<>(reqDto.getPage(), reqDto.getPageSize());
        Page<SysRole> pageResult = this.page(
                page,
                Wrappers.<SysRole>lambdaQuery()
                        .eq(StrUtil.isNotBlank(reqDto.getRoleName()), SysRole::getRoleName, reqDto.getRoleName())
                        .eq(StrUtil.isNotBlank(reqDto.getRoleCode()), SysRole::getRoleCode, reqDto.getRoleCode())
                        .eq(reqDto.getStatus() != null, SysRole::getStatus, reqDto.getStatus())
                        .orderByAsc(SysRole::getSort)
        );
        pageResult.getRecords().forEach(item -> {
            List<SysRolePermission> sysRolePermissions = iSysRolePermissionService.getRolePermissionByRoleId(item.getId());
            List<Long> permissionIds = sysRolePermissions.stream().map(SysRolePermission::getPermissionId).collect(Collectors.toList());
            item.setPermissionIds(permissionIds);
        });

        PageResult<SysRole> result = new PageResult<>();
        result.setRecords(pageResult.getRecords());
        result.setTotal(pageResult.getTotal());
        result.setPage(pageResult.getCurrent());
        result.setPageSize(pageResult.getSize());
        result.setPages(pageResult.getPages());
        return result;
    }

    @Override
    public List<SysRole> allRoleList() {
        List<SysRole> sysRoles = this.list(
                Wrappers.<SysRole>lambdaQuery()
                        .orderByAsc(SysRole::getSort)
        );
        return sysRoles;
    }

    @Override
    public SysRole getRoleByUserId(Long userId) {
        SysUserRole sysUserRole = iSysUserRoleService.getOne(Wrappers.<SysUserRole>lambdaQuery().eq(SysUserRole::getUserId, userId));
        if (sysUserRole != null) {
            return this.getOne(
                    Wrappers.<SysRole>lambdaQuery()
                            .eq(SysRole::getId, sysUserRole.getRoleId())
                            .eq(SysRole::getStatus, 1)
            );
        }
        return null;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean add(AddRoleReqDto reqDto) {
        SysRole sysRole = BeanUtil.copyProperties(reqDto, SysRole.class);
        this.save(sysRole);

        if (CollUtil.isNotEmpty(reqDto.getPermissionIds())) {
            verifyPermissionsCount(reqDto);
            List<SysRolePermission> saveSysRolePermissions = reqDto.getPermissionIds().stream().map(item -> {
                SysRolePermission sysRolePermission = new SysRolePermission();
                sysRolePermission.setRoleId(sysRole.getId());
                sysRolePermission.setPermissionId(item);
                return sysRolePermission;
            }).toList();
            iSysRolePermissionService.saveBatch(saveSysRolePermissions);
        }
        return Boolean.TRUE;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean setRoleStatus(SetRoleStatusReqDto reqDto) {
        SysRole sysRole = this.getById(reqDto.getId());
        if (sysRole == null) {
            throw new ApiException("角色不存在");
        }
        sysRole.setStatus(reqDto.getStatus());
        return this.updateById(sysRole);
    }

    @Override
    public Boolean update(UpdateRoleReqDto reqDto) {
        SysRole sysRole = this.getById(reqDto.getId());
        if (sysRole == null) {
            throw new ApiException("角色不存在");
        }
        BeanUtil.copyProperties(reqDto, sysRole);
        this.updateById(sysRole);

        if (CollUtil.isNotEmpty(reqDto.getPermissionIds())) {
            verifyPermissionsCount(reqDto);
            List<SysRolePermission> sysRolePermissions = iSysRolePermissionService.getRolePermissionByRoleId(reqDto.getId());
            List<Long> oldPermissionIds = sysRolePermissions.stream().map(SysRolePermission::getPermissionId).toList();
            List<Long> newPermissionIds = reqDto.getPermissionIds();
            // 差集
            Collection<Long> disjunction = CollUtil.disjunction(oldPermissionIds, newPermissionIds);
            // 新数据 交集 需要新增的
            Collection<Long> newIntersection = CollUtil.intersection(disjunction, newPermissionIds);
            // 旧数据 交集 需要删除的
            Collection<Long> oldIntersection = CollUtil.intersection(disjunction, oldPermissionIds);
            if (CollUtil.isNotEmpty(disjunction)) {
                if (CollUtil.isNotEmpty(oldIntersection)) {
                    iSysRolePermissionService.remove(
                            Wrappers.<SysRolePermission>lambdaQuery()
                                    .eq(SysRolePermission::getRoleId, reqDto.getId())
                                    .in(SysRolePermission::getPermissionId, oldIntersection));
                }
                if (CollUtil.isNotEmpty(newIntersection)) {
                    List<SysRolePermission> saveSysRolePermissions = newIntersection.stream().map(item -> {
                        SysRolePermission sysRolePermission = new SysRolePermission();
                        sysRolePermission.setRoleId(sysRole.getId());
                        sysRolePermission.setPermissionId(item);
                        return sysRolePermission;
                    }).toList();
                    iSysRolePermissionService.saveBatch(saveSysRolePermissions);
                }
            }
        }
        return Boolean.TRUE;
    }

    /**
     * 校验权限数量
     *
     * @param reqDto
     */
    private void verifyPermissionsCount(AddRoleReqDto reqDto) {
        List<SysPermission> sysPermissions = iSysPermissionService.list(Wrappers.<SysPermission>lambdaQuery().in(SysPermission::getId, reqDto.getPermissionIds()));
        if (sysPermissions.size() != reqDto.getPermissionIds().size()) {
            throw new ApiException("选择权限数据错误，操作失败");
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean delete(Long id) {
        SysRole sysRole = this.getById(id);
        if (sysRole == null) {
            throw new ApiException("角色不存在");
        }
        iSysUserRoleService.removeUserRoleByRoleId(id);
        iSysRolePermissionService.removeRolePermissionByRoleId(id);
        return this.removeById(id);
    }

}
